Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


docs/agents/skills/meshchat-orchestration-split/SKILL.md dev (af76f09d) Text, 3.54 KB

Tc9d1d9# Skill: meshchat-orchestration-split

Extract or split HTTP routes and WebSocket handlers under Ta5d6ff`meshchatx/src/backend/http/`
without changing behaviour.

Tc9d1d9## When to use

Tff7b72- Splitting or moving handlers among Ta5d6ff`routes/<domain>.py` modules
Tff7b72- Moving WS inbound dispatch pieces among Ta5d6ff`ws/handlers_*.py`
Tff7b72- Adding new HTTP endpoints or WS message types in the extracted layout

Also read:

Tff7b72- Ta5d6ff`docs/agents/module-ownership.md`
Tff7b72- Ta5d6ff`docs/agents/conventions/backend.md`
Tff7b72- Ta5d6ff`docs/agents/conventions/tests.md`

Tc9d1d9## Hard rules

Tff7b721. Mechanical extract only. No renames, no error-map tweaks, no new logging in the same change as a move.
Tff7b722. One concern per change: move or behaviour, never both.
Tff7b723. Keep public entrypoints:
Tff7b72- Ta5d6ff`from meshchatx.meshchat import ReticulumMeshChat, main`
Tff7b72- Ta5d6ff`get_routes()` and Ta5d6ff`_define_routes(routes)` return shape
Tff7b72- middleware order: Ta5d6ff`auth`, Ta5d6ff`mime_type`, Ta5d6ff`security`, Ta5d6ff`csrf`, Ta5d6ff`ip_allowlist`
Tff7b724. Handlers use Ta5d6ff`app` where the original used Ta5d6ff`self`.
Tff7b725. No new business logic in route modules. Parse, call manager or app method, return response.
Tff7b726. Identity lifecycle and LXMF callbacks stay on Ta5d6ff`ReticulumMeshChat` until lifecycle packaging.
Tff7b727. Follow inventory names in Ta5d6ff`docs/agents/module-ownership.md`. Do not invent alternate folders.
Tff7b728. Domain splits start from existing Ta5d6ff`routes/<domain>.py` modules or residual shared helpers.
Do not re-extract routes from Ta5d6ff`meshchat.py`.
Tff7b729. One-shot extract scripts that rewrote Ta5d6ff`meshchat.py` were removed. Do not revive them.

Tc9d1d9## Layout

Current:

Ta5d6ff```
meshchatx/src/backend/http/
context.py
errors.py
live_names.py
meshchat_names.py
middleware.py
register.py
routes/<domain>.py
routes/__init__.py
ws/dispatch.py
ws/handlers_*.py
```

Pattern:

Ta5d6ff```Ta5d6ffpython
Tff7b72def Td2a8ffregister_status_routesTb4b4b4(Te6edf3routesTb4b4b4, Te6edf3appTb4b4b4)Tb4b4b4:
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/statusTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffstatusTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72.Tff7b72.Tff7b72.
Ta5d6ff```

Ta5d6ff`register.py` calls Ta5d6ff`register_extracted_routes`, which binds meshchat free names via
Ta5d6ff`live_names.inject_meshchat_names` so Ta5d6ff`patch("meshchatx.meshchat.<symbol>")` still applies.

Lazy-import Ta5d6ff`register_all_routes` from inside Ta5d6ff`_define_routes` so route modules load after
meshchat is initialized.

Tc9d1d9## Contract scanners

Scanners must cover:

Tff7b72- Ta5d6ff`meshchatx/meshchat.py`
Tff7b72- Ta5d6ff`meshchatx/src/backend/http/**/*.py`
Tff7b72- lifecycle modules for broadcast payloads where relevant

HTTP: Ta5d6ff`tests/backend/http_api_contract_helpers.py` (Ta5d6ff`extract_meshchat_http_routes`).

WS: Ta5d6ff`tests/backend/ws_contract_helpers.py` (inbound, direct responses, broadcast).

Update fixtures only when inventory intentionally changes:

Ta5d6ff```Ta5d6ffbash
Te6edf3UPDATE_HTTP_API_ROUTESTff7b72=T79c0ff1 uv run pytest tests/backend/test_http_api_contract.py -k meshchat_http_routes_match_fixture
Te6edf3UPDATE_WS_MESSAGE_MANIFESTTff7b72=T79c0ff1 uv run pytest tests/backend/test_ws_json_contracts.py -k manifest_matches_meshchat
Ta5d6ff```

Tc9d1d9## Verification

After each domain move:

Ta5d6ff```Ta5d6ffbash
uv run pytest tests/backend/test_http_api_contract.py Tffea00\
tests/backend/test_api_json_contracts.py Tffea00\
tests/backend/test_http_api_json_contracts_broad.py Tffea00\
tests/backend/test_ws_json_contracts.py -q --tbTff7b72=short
Ta5d6ff```

Also run domain tests for the moved area and Ta5d6ff`task test:quick` at milestones.

Before declaring a large milestone done: Ta5d6ff`task test:backend` and Ta5d6ff`task test:frontend`.

Tc9d1d9## Compatibility patches

Tests often use Ta5d6ff`patch("meshchatx.meshchat.<symbol>")`. Keep those symbols importable from
Ta5d6ff`meshchatx.meshchat` (re-export if moved). Live name proxies live in Ta5d6ff`backend/http/live_names.py`.

Ta5d6ff`ReticulumMeshChat.on_websocket_data_received` is a one-line delegate to Ta5d6ff`http/ws/dispatch.py`.


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────